package com.lu.nio;

import com.lu.nio.ChannelHandler;
import com.sun.security.ntlm.Server;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Set;

/**
 * @program lu-netty
 * @description:
 * @author: zhanglu
 * @create: 2022-06-10 16:11:00
 */
public abstract class ChannelAdapter extends Thread{

    private Selector selector;
    private String charset;
    protected ChannelHandler ctx;

    public ChannelAdapter(Selector selector, String charset){
        this.selector = selector;
        this.charset = charset;
    }

    @Override
    public void run() {
        while (true){
            //1s执行一次
            try {
                selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey key : selectionKeys) {
                    this.handlerInput(key);
                }
            } catch (Exception ignore) {
            }
        }
    }

    private void handlerInput(SelectionKey key) throws IOException {
        if(!key.isValid()){
            return;
        }
        //处理连接事件
        Class<?> superclass = key.channel().getClass().getSuperclass();
        //客户端SocketChannel
        if(superclass == SocketChannel.class){
            this.clientConnect(key);
        }
        //服务端ServerSocketChannel
        if(superclass == ServerSocketChannel.class){
            this.serverConnect(key);
        }
        //处理读事件
        this.readEventHandler(key);
    }

    public void clientConnect(SelectionKey key) throws IOException {
        if(!key.isConnectable()){
            return;
        }
        SocketChannel channel = (SocketChannel) key.channel();
        if(!channel.finishConnect()){
            System.exit(1);
        }
        ctx = new ChannelHandler(channel, charset);
        channelActive();
        channel.register(selector, SelectionKey.OP_READ);
    }

    public void serverConnect(SelectionKey key) throws IOException {
        if(!key.isAcceptable()){
            return;
        }
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        SocketChannel socketChannel = channel.accept();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        ctx = new ChannelHandler(socketChannel, charset);
        channelActive();
    }

    public void readEventHandler(SelectionKey key) throws IOException {
        if(!key.isReadable()){
            return;
        }
        SocketChannel socketChannel  = (SocketChannel) key.channel();
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        int readBytes = socketChannel.read(readBuffer);
        if(readBytes == 0){
            return;
        }
        if(readBytes < 0){
            key.cancel();
            socketChannel.close();
            return;
        }
        readBuffer.flip();
        byte[] bytes = new byte[readBuffer.remaining()];
        readBuffer.get(bytes);
        channelRead(new String(bytes, charset));
    }

    //连接通知 - 处理器
    protected abstract void channelActive();

    //读取消息 - 处理器
    protected abstract void channelRead(Object msg);


}
